package com.team2.cyber_eye.ActivityHelpers;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.google.android.gms.maps.model.LatLng;
import com.team2.cyber_eye.MapDirectionList;
import com.team2.shared.Direction;
import com.team2.shared.MapDirectionInfo;

public class DirectionsJSONParser {
	
	/** Receives a JSONObject and returns a list of lists containing latitude and longitude */
	public List<List<HashMap<String,String>>> parse(JSONObject jObject){
		
		List<List<HashMap<String, String>>> routes = new ArrayList<List<HashMap<String,String>>>() ;
		JSONArray jRoutes = null;
		JSONArray jLegs = null;
		JSONArray jSteps = null;	
		
		try {			
			
			jRoutes = jObject.getJSONArray("routes");
			
			/** Traversing all routes */
			for(int i=0;i<jRoutes.length();i++){			
				jLegs = ( (JSONObject)jRoutes.get(i)).getJSONArray("legs");
				List path = new ArrayList<HashMap<String, String>>();
				
				/** Traversing all legs */
				for(int j=0;j<jLegs.length();j++){
					jSteps = ( (JSONObject)jLegs.get(j)).getJSONArray("steps");
					
					/** Traversing all steps */
					for(int k=0;k<jSteps.length();k++){
						String polyline = "";
						polyline = (String)((JSONObject)((JSONObject)jSteps.get(k)).get("polyline")).get("points");
						List<LatLng> list = decodePoly(polyline);
						
						/** Traversing all points */
						for(int l=0;l<list.size();l++){
							HashMap<String, String> hm = new HashMap<String, String>();
							hm.put("lat", Double.toString(((LatLng)list.get(l)).latitude) );
							hm.put("lng", Double.toString(((LatLng)list.get(l)).longitude) );
							path.add(hm);						
						}								
					}
					routes.add(path);
					
					break;
				}
			}
			
		} catch (JSONException e) {			
			e.printStackTrace();
		}catch (Exception e){			
		}
		
		
		return routes;
	}
	
	/** Receives a JSONObject and returns a list of lists containing latitude and longitude */
	public MapDirectionInfo parseDirectionInfo(JSONObject jObject){
		
		MapDirectionInfo mapInfoObj = new MapDirectionInfo();
		JSONArray jRoutes = null;
		JSONArray jLegs = null;	
		
		try {			
			
			jRoutes = jObject.getJSONArray("routes");
			
			/** Traversing all routes */
			for(int i=0;i<jRoutes.length();i++){			
				jLegs = ( (JSONObject)jRoutes.get(i)).getJSONArray("legs");
				
				/** Traversing all legs */
				for(int j=0;j<jLegs.length();j++){
					String distance = "";
					distance = (String)((JSONObject)((JSONObject)jLegs.get(j)).get("distance")).get("text");
					
					String timeToDistance = "";
					timeToDistance = (String)((JSONObject)((JSONObject)jLegs.get(j)).get("duration")).get("text");
					
					String tempFromAddress = "";
					tempFromAddress = (String)((JSONObject)jLegs.get(j)).get("start_address");
					
					String fromStreetAddr = "";
					fromStreetAddr = parseAddress(tempFromAddress, "streetAddress");
					
					String fromCity = "";
					fromCity = parseAddress(tempFromAddress, "City");
					
					String fromStateAndZipCode = "";
					fromStateAndZipCode = parseAddress(tempFromAddress, "StateZipCode");
					
					String fromCountry = "";
					fromCountry = parseAddress(tempFromAddress, "Country");
					
					String tempToAddress = "";
					tempToAddress = (String)((JSONObject)jLegs.get(j)).get("end_address");
					
					String toStreetAddr = "";
					toStreetAddr = parseAddress(tempToAddress, "streetAddress");
					
					String toCity = "";
					toCity = parseAddress(tempToAddress, "City");
					
					String toStateAndZipCode = "";
					toStateAndZipCode = parseAddress(tempToAddress, "StateZipCode");
					
					String toCountry = "";
					toCountry = parseAddress(tempToAddress, "Country");
					
					mapInfoObj.setFromStreetAddr(fromStreetAddr);
					mapInfoObj.setFromCity(fromCity);
					mapInfoObj.setFromStateAndZipCode(fromStateAndZipCode);
					mapInfoObj.setFromCountry(fromCountry);
					
					mapInfoObj.setToStreetAddr(toStreetAddr);
					mapInfoObj.setToCity(toCity);
					mapInfoObj.setToStateAndZipCode(toStateAndZipCode);
					mapInfoObj.setToCountry(toCountry);
					
					mapInfoObj.setDistanceToDest(distance);
					mapInfoObj.setTimeToDest(timeToDistance);
					
				}
				
				break;
			}
			
		} catch (JSONException e) {			
			e.printStackTrace();
		}catch (Exception e){			
		}
		
		
		return mapInfoObj;
	}
	
	/** Receives a JSONObject and returns a list of lists containing latitude and longitude */
	public ArrayList<Direction> parseDirectionList(JSONObject jObject){
		
		ArrayList<Direction> directionList = new ArrayList<Direction>();
		JSONArray jRoutes = null;
		JSONArray jLegs = null;
		JSONArray jSteps = null;	
		
		try {			
			
			jRoutes = jObject.getJSONArray("routes");
			
			/** Traversing all routes */
			for(int i=0;i<jRoutes.length();i++){			
				jLegs = ( (JSONObject)jRoutes.get(i)).getJSONArray("legs");
				
				
				/** Traversing all legs */
				for(int j=0;j<jLegs.length();j++){
					jSteps = ( (JSONObject)jLegs.get(j)).getJSONArray("steps");
					
					/** Traversing all steps */
					for(int k=0;k<jSteps.length();k++){
						
						Direction obj = new Direction();
						
						String distance = "";
						distance = (String)((JSONObject)((JSONObject)jSteps.get(k)).get("distance")).get("text");
				
						String tempPath = "";
						tempPath = (String)((JSONObject)jSteps.get(k)).get("html_instructions");
						
						String path = "";
						path = parsePath(tempPath);
						
						obj.setDirectionDesc(path);
						obj.setDistance(distance);
						
						directionList.add(obj);
												
					}
					
				}
				
				break;
			}
			
		} catch (JSONException e) {			
			e.printStackTrace();
		}catch (Exception e){			
		}
		
		
		return directionList;
	}
	
	private String parsePath(String path){
		String parsedPath = "";
		boolean found = false;
		
		if(path.length() > 0){
			
			if(path.contains("<div style=\"font-size:0.9em\">")){
				parsedPath = path.replace("<div style=\"font-size:0.9em\">", " - ");
				found = true;
			}
			
			if(parsedPath.contains("</div>")){
				parsedPath = parsedPath.replace("</div>", "");
			}
			
			if(!found){
				return path;
			}
		}
		
		return parsedPath;
	}
	
	private String parseAddress(String address, String type){
		String parsedAddr = "";
		try{
			if(address.length() > 0){
				String[] tempAddr = address.split(",");
				
				if(type == "streetAddress"){
					parsedAddr = tempAddr[0];
				}else if(type == "City"){
					parsedAddr = tempAddr[tempAddr.length - 3];
				}else if(type == "StateZipCode"){
					parsedAddr = tempAddr[tempAddr.length - 2];
				}else if(type == "Country"){
					parsedAddr = tempAddr[tempAddr.length - 1];
				}
			}
		}catch(Exception e){
			parsedAddr = "";
		}
				
		return parsedAddr;
	}
	
	
	/**
	 * Method to decode polyline points 
	 * Courtesy : http://jeffreysambells.com/2010/05/27/decoding-polylines-from-google-maps-direction-api-with-java 
	 * */
    private List<LatLng> decodePoly(String encoded) {

        List<LatLng> poly = new ArrayList<LatLng>();
        int index = 0, len = encoded.length();
        int lat = 0, lng = 0;

        while (index < len) {
            int b, shift = 0, result = 0;
            do {
                b = encoded.charAt(index++) - 63;
                result |= (b & 0x1f) << shift;
                shift += 5;
            } while (b >= 0x20);
            int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
            lat += dlat;

            shift = 0;
            result = 0;
            do {
                b = encoded.charAt(index++) - 63;
                result |= (b & 0x1f) << shift;
                shift += 5;
            } while (b >= 0x20);
            int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
            lng += dlng;

            LatLng p = new LatLng((((double) lat / 1E5)),
                    (((double) lng / 1E5)));
            poly.add(p);
        }

        return poly;
    }
}
